package com.cf.base.http.core;

import com.cf.base.http.generator.BaseBodyErrorAdapter;
import com.cf.base.http.generator.IErrorAdapter;
import com.cf.base.http.generator.GeneratorMethod;
import com.cf.base.http.interceptor.HeaderInterceptor;
import com.cf.base.http.interceptor.headers.HeaderProvider;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;

import io.reactivex.Observable;
import io.reactivex.ObservableSource;
import io.reactivex.functions.Function;
import okhttp3.OkHttpClient;
import retrofit2.CallAdapter;
import retrofit2.Converter;
import retrofit2.Retrofit;

/**
 * @author yangji
 */
public class RetrofitService {

    /**
     * 构建网络框架
     */
    public static class RetrofitBeanBuilder implements IHttpBuilder.ICfBuilder {

        private OkHttpClient.Builder httpBuilder;
        private String moduleKey;
        private String baseUrl;
        private Converter.Factory converterFactory;
        private CallAdapter.Factory callFactory;
        private IErrorAdapter errorAdapter;
        private HeaderProvider headerProvider;

        private RetrofitBeanBuilder() {
        }

        public static IHttpBuilder.ICfHttpModuleName create() {
            return new RetrofitBeanBuilder();
        }

        @Override
        public IHttpBuilder.ICfHttpUrl moduleName(String moduleName) {
            this.moduleKey = moduleName;
            return this;
        }

        @Override
        public IHttpBuilder.ICfClient baseUrl(String url) {
            this.baseUrl = url;
            return this;
        }

        @Override
        public IHttpBuilder.ICfHeader client(OkHttpClient.Builder builder) {
            this.httpBuilder = builder;
            return this;
        }

        @Override
        public IHttpBuilder.ICfErrorAdapter retrofitFactory(Converter.Factory converterFactory, CallAdapter.Factory callFactory) {
            this.converterFactory = converterFactory;
            this.callFactory = callFactory;
            return this;
        }

        @Override
        public IHttpBuilder.ICfBuilder errorAdapter(BaseBodyErrorAdapter adapter) {
            this.errorAdapter = adapter;
            return this;
        }

        @Override
        public RetrofitService build() {
            Retrofit retrofit = new Retrofit.Builder().baseUrl(baseUrl)
                    .client(httpBuilder
                            .addInterceptor(new HeaderInterceptor(headerProvider))
                            .build())
                    .addCallAdapterFactory(callFactory)
                    .addConverterFactory(converterFactory)
                    .build();
            RetrofitService bean = new RetrofitService(retrofit, errorAdapter);
            RetrofitManager.getInstance().addRetrofitBean(moduleKey, bean);
            return bean;
        }

        @Override
        public IHttpBuilder.ICfRetrofitFactory header(HeaderProvider provider) {
            this.headerProvider = provider;
            return this;
        }
    }


    private Retrofit retrofit;
    private Map<Class<?>, Object> servicesApi;
    private IErrorAdapter adapter;

    public RetrofitService(Retrofit retrofit, IErrorAdapter errorAdapter) {
        this.retrofit = retrofit;
        this.servicesApi = new HashMap<>();
        this.adapter = errorAdapter;
    }

    /**
     * 创建 servicesApi
     *
     * @param cls 需要实例的 servicesApi
     * @param <T> 需要实例的 servicesApi 对象类型
     * @return 实例化serviceApi
     */
    public <T> T create(Class<T> cls) {
        if (servicesApi.containsKey(cls)) {
            return (T) servicesApi.get(cls);
        }
        T serviceApi = create(retrofit, cls);
        servicesApi.put(cls, serviceApi);
        return serviceApi;
    }

    @SuppressWarnings("unchecked")
    private <T> T create(Retrofit retrofit, Class<T> tClass) {
        T serviceApi = retrofit.create(tClass);
        return (T) Proxy.newProxyInstance(tClass.getClassLoader(),
                new Class[]{tClass},
                new ErrorProxyHandler<T>(serviceApi));
    }

    public IErrorAdapter getAdapter() {
        return adapter;
    }

    class ErrorProxyHandler<T> implements InvocationHandler {

        private final T serviceApi;

        private ErrorProxyHandler(T serviceApi) {
            this.serviceApi = serviceApi;
        }

        @Override
        public Object invoke(Object proxy, final Method method, Object[] args) throws Throwable {
            if (method.getDeclaringClass() == Object.class) {
                return method.invoke(this, args);
            }

            Object result = null;
            try {
                if (args == null) {
                    result = method.invoke(serviceApi);
                } else {
                    result = method.invoke(serviceApi, args);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

            if (result == null) {
                return null;
            }

            if (!(result instanceof Observable)) {
                return result;
            }

            Observable<Object> observable = (Observable) result;
            return observable
                    .onErrorResumeNext(new Function<Throwable, ObservableSource<?>>() {
                        @Override
                        public ObservableSource<?> apply(final Throwable throwable) throws Exception {
                            return Observable.error(GeneratorMethod.generatorError(RetrofitService.this, method, throwable));
                        }
                    })
//                    .onErrorReturn(new Function<Throwable, Object>() {
//                        @Override
//                        public Object apply(Throwable throwable) throws Exception {
//                            return GeneratorMethod.generator(RetrofitService.this, method, throwable);
//                        }
//                    })
                    ;

        }

    }
}
